﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace PPSkin
{
    public partial class PPListBox : ListBox
    {
        private ToolTip tip = new ToolTip();

        private Color itemBaseColor = Color.White;
        private Color itemTextColor = Color.Black;
        private Color itemSelectBaseColor = Color.LightGray;
        private Color itemSelectTextColor = Color.Black;

        [Description("是否显示序号"), Category("PPSkin")]
        public bool ShowSerialNumber { get; set; } = false;

        [Description("正常背景色"), Category("PPSkin")]
        public Color ItemBaseColor
        {
            get { return itemBaseColor; }
            set
            {
                itemBaseColor = value;
                this.Invalidate();
            }
        }

        [Description("正常文本色"), Category("PPSkin")]
        public Color ItemTextColor
        {
            get { return itemTextColor; }
            set
            {
                itemTextColor = value;
                this.Invalidate();
            }
        }

        [Description("鼠标选中背景色"), Category("PPSkin")]
        public Color ItemSelectBaseColor
        {
            get { return itemSelectBaseColor; }
            set
            {
                itemSelectBaseColor = value;
                this.Invalidate();
            }
        }

        [Description("鼠标选中文本色"), Category("PPSkin")]
        public Color ItemSelectTextColor
        {
            get { return itemSelectTextColor; }
            set
            {
                itemSelectTextColor = value;
                this.Invalidate();
            }
        }

        [Description("选中序号"), Category("PPSkin")]
        public int ChooseIndex { get; set; } = -1;

        [Description("选中文本色"), Category("PPSkin")]
        public Color ChooseTextColor { get; set; } = Color.DodgerBlue;

        [Description("文本绘制模式"), Category("PPSkin")]
        public textDrawMode TextDrawMode { get; set; } = textDrawMode.Anti;

        public enum textDrawMode
        {
            Anti,
            Clear
        }

        [Description("文本对齐方式"), Category("PPSkin")]
        public TextAligns TextAlign { get; set; } = TextAligns.Left;

        public enum TextAligns
        {
            Left,
            Center,
            Right
        }

        public PPListBox()
        {
            InitializeComponent();
            this.DrawMode = DrawMode.OwnerDrawFixed;
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            //this.SetStyle(ControlStyles.Selectable, true);
            //this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            //this.SetStyle(ControlStyles.UserPaint, true);
            this.UpdateStyles();
        }

        //protected override CreateParams CreateParams
        //{
        //    get
        //    {
        //        CreateParams cp = base.CreateParams;
        //        cp.ExStyle |= 0x02000000;//用双缓冲绘制窗口的所有子控件
        //        return cp;
        //    }
        //}

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            // base.OnDrawItem(e);

            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            e.Graphics.TextRenderingHint = TextDrawMode == textDrawMode.Anti ? System.Drawing.Text.TextRenderingHint.AntiAlias : System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            StringFormat stringFormat = new StringFormat();
            stringFormat.LineAlignment = StringAlignment.Center;
            stringFormat.FormatFlags = StringFormatFlags.LineLimit;
            stringFormat.Trimming = StringTrimming.EllipsisCharacter;

            switch (TextAlign)
            {
                case TextAligns.Left: stringFormat.Alignment = StringAlignment.Near; break;
                case TextAligns.Center: stringFormat.Alignment = StringAlignment.Center; break;
                case TextAligns.Right: stringFormat.Alignment = StringAlignment.Far; break;
            }

            Brush backbrush = new SolidBrush(ItemBaseColor);
            Brush textbrush = new SolidBrush(ItemTextColor);

            if (this.SelectedIndex == e.Index)
            {
                backbrush = new SolidBrush(ItemSelectBaseColor);
                textbrush = new SolidBrush(ItemSelectTextColor);
            }

            if (e.Index == ChooseIndex)
            {
                textbrush = new SolidBrush(ChooseTextColor);
            }

            Bitmap bitmap = new Bitmap(e.Bounds.Width, e.Bounds.Height);
            Graphics g = Graphics.FromImage(bitmap);
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.TextRenderingHint = TextDrawMode == textDrawMode.Anti ? System.Drawing.Text.TextRenderingHint.AntiAlias : System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            g.FillRectangle(backbrush, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
            if (this.Items.Count > 0)
            {
                string text = this.GetItemText(this.Items[e.Index]);
                if (ShowSerialNumber)
                {
                    text = (e.Index + 1).ToString() + "." + text;
                }

                g.DrawString(text, e.Font, textbrush, new Rectangle(0, 0, bitmap.Width, bitmap.Height), stringFormat);
            }
            e.Graphics.DrawImage(bitmap, e.Bounds);
            g.Dispose();
            bitmap.Dispose();

            backbrush.Dispose();
            textbrush.Dispose();
            stringFormat.Dispose();
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            int mouseIndex = IndexFromPoint(this.PointToClient(MousePosition));
            if (mouseIndex != -1)
            {
                string text = this.GetItemText(this.Items[mouseIndex]);
                if (ShowSerialNumber)
                {
                    text = (mouseIndex + 1).ToString() + "." + text;
                }

                Size textsize = TextRenderer.MeasureText(text, this.Font);

                if (textsize.Width > this.Width)
                {
                    if (tip.GetToolTip(this) != text)
                    {
                        tip.SetToolTip(this, text);
                    }
                }
                else
                {
                    tip.SetToolTip(this, "");
                }
            }
            else
            {
                tip.SetToolTip(this, "");
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            tip.SetToolTip(this, "");
        }

        protected override void OnMouseDoubleClick(MouseEventArgs e)
        {
            int mouseIndex = IndexFromPoint(e.Location);
            if (mouseIndex != -1)
            {
                ChooseIndex = mouseIndex;
                this.Invalidate();
            }
            base.OnMouseDoubleClick(e);
        }
    }
}